package io.zrpc.core.common.utils;

/**
 * <p>类型转换工具类</p>
 * <p>调用端时将类描述转换为字符串传输。服务端将字符串转换为具体的类</p>
 * <pre>
 *     保证传递的时候值为可阅读格式，而不是jvm格式（[Lxxx;）：
 *     普通：java.lang.String、java.lang.String[]
 *     基本类型：int、int[]
 *     内部类：com.example.Inner、com.example.Inner[]
 *     匿名类：com.example.Xxx$1、com.example.Xxx$1[]
 *     本地类：com.example.Xxx$1Local、com.example.Xxx$1Local[]
 *     成员类：com.example.Xxx$Member、com.example.Xxx$Member[]
 * 同时Class.forName的时候又会解析出Class。
 * </pre>
 * <p>
 */
public class ClassTypeUtils {

    /**
     * String[] 转 Class[]
     *
     * @param typeStrs 对象描述[]
     * @return Class[]
     */
    public static Class<?>[] getClasses(String[] typeStrs) throws RuntimeException {
        if (CommonUtils.isEmpty(typeStrs)) {
            return new Class[0];
        } else {
            Class<?>[] classes = new Class[typeStrs.length];
            for (int i = 0; i < typeStrs.length; i++) {
                classes[i] = getClass(typeStrs[i]);
            }
            return classes;
        }
    }

    /**
     * String转Class
     *
     * @param typeStr 对象描述
     * @return Class[]
     */
    public static Class<?> getClass(String typeStr) {
        Class<?> clazz = ReflectCacheUtils.getClassCache(typeStr);
        if (clazz == null) {
            if ("void".equals(typeStr)) {
                clazz = void.class;
            } else if ("boolean".equals(typeStr)) {
                clazz = boolean.class;
            } else if ("byte".equals(typeStr)) {
                clazz = byte.class;
            } else if ("char".equals(typeStr)) {
                clazz = char.class;
            } else if ("double".equals(typeStr)) {
                clazz = double.class;
            } else if ("float".equals(typeStr)) {
                clazz = float.class;
            } else if ("int".equals(typeStr)) {
                clazz = int.class;
            } else if ("long".equals(typeStr)) {
                clazz = long.class;
            } else if ("short".equals(typeStr)) {
                clazz = short.class;
            } else {
                String jvmName = canonicalNameToJvmName(typeStr);
                clazz = ClassUtils.forName(jvmName);
            }
            ReflectCacheUtils.putClassCache(typeStr, clazz);
        }
        return clazz;
    }

    /**
     * 通用描述转JVM描述
     *
     * @param canonicalName 例如 int[]
     * @return JVM描述 例如 [I;
     */
    public static String canonicalNameToJvmName(String canonicalName) {
        boolean isArray = canonicalName.endsWith("[]");
        if (isArray) {
            StringBuilder t = new StringBuilder(); // 计数，看上几维数组
            while (isArray) {
                canonicalName = canonicalName.substring(0, canonicalName.length() - 2);
                t.append("[");
                isArray = canonicalName.endsWith("[]");
            }
            switch (canonicalName) {
                case "boolean":
                    canonicalName = t + "Z";
                    break;
                case "byte":
                    canonicalName = t + "B";
                    break;
                case "char":
                    canonicalName = t + "C";
                    break;
                case "double":
                    canonicalName = t + "D";
                    break;
                case "float":
                    canonicalName = t + "F";
                    break;
                case "int":
                    canonicalName = t + "I";
                    break;
                case "long":
                    canonicalName = t + "J";
                    break;
                case "short":
                    canonicalName = t + "S";
                    break;
                default:
                    canonicalName = t + "L" + canonicalName + ";";
                    break;
            }
        }
        return canonicalName;
    }

    /**
     * Class[]转String[] <br>
     * 注意，得到的String可能不能直接用于Class.forName，请使用getClasses(String[])反向获取
     *
     * @param types Class[]
     * @return 对象描述
     * @see #getClasses(String[])
     */
    public static String[] getTypeStrs(Class<?>[] types) {
        return getTypeStrs(types, false);
    }

    /**
     * Class[]转String[] <br>
     * 注意，得到的String可能不能直接用于Class.forName，请使用getClasses(String[])反向获取
     *
     * @param types Class[]
     * @param javaStyle JDK自带格式，例如 int[], true的话返回 [I; false的话返回int[]
     * @return 对象描述
     * @see #getClasses(String[])
     */
    public static String[] getTypeStrs(Class<?>[] types, boolean javaStyle) {
        if (CommonUtils.isEmpty(types)) {
            return StringUtils.EMPTY_STRING_ARRAY;
        } else {
            String[] strings = new String[types.length];
            for (int i = 0; i < types.length; i++) {
                strings[i] = javaStyle ? types[i].getName() : getTypeStr(types[i]);
            }
            return strings;
        }
    }

    /**
     * Class转String<br>
     * 注意，得到的String可能不能直接用于Class.forName，请使用getClass(String)反向获取
     *
     * @param clazz Class
     * @return 对象
     * @see #getClass(String)
     */
    public static String getTypeStr(Class<?> clazz) {
        String typeStr = ReflectCacheUtils.getTypeStrCache(clazz);
        if (typeStr == null) {
            if (clazz.isArray()) {
                String name = clazz.getName(); // 原始名字：[Ljava.lang.String;
                typeStr = jvmNameToCanonicalName(name); // java.lang.String[]
            } else {
                typeStr = clazz.getName();
            }
            ReflectCacheUtils.putTypeStrCache(clazz, typeStr);
        }
        return typeStr;
    }

    /**
     * JVM描述转通用描述
     *
     * @param jvmName 例如 [I;
     * @return 通用描述 例如 int[]
     */
    public static String jvmNameToCanonicalName(String jvmName) {
        boolean isArray = jvmName.charAt(0) == '[';
        if (isArray) {
            StringBuilder cnName = new StringBuilder(StringUtils.EMPTY); // 计数，看上几维数组
            int i = 0;
            for (; i < jvmName.length(); i++) {
                if (jvmName.charAt(i) != '[') {
                    break;
                }
                cnName.append("[]");
            }
            String componentType = jvmName.substring(i, jvmName.length());
            switch (componentType) {
                case "Z":
                    cnName.insert(0, "boolean");
                    break;
                case "B":
                    cnName.insert(0, "byte");
                    break;
                case "C":
                    cnName.insert(0, "char");
                    break;
                case "D":
                    cnName.insert(0, "double");
                    break;
                case "F":
                    cnName.insert(0, "float");
                    break;
                case "I":
                    cnName.insert(0, "int");
                    break;
                case "J":
                    cnName.insert(0, "long");
                    break;
                case "S":
                    cnName.insert(0, "short");
                    break;
                default:
                    cnName.insert(0, componentType.substring(1, componentType.length() - 1)); // 对象的 去掉L

                    break;
            }
            return cnName.toString();
        }
        return jvmName;
    }
}